package com.picturehistory.core.jersey.model;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.appengine.api.datastore.Key;
import com.picturehistory.core.jersey.util.AES;
import com.picturehistory.core.jersey.util.PIN;


@XmlRootElement(name="User")
@XmlType(propOrder={"key", "userId", "idNumber", "articles"})
@XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.FIELD)
@PersistenceCapable
public class User {

	@XmlTransient
	private final Logger logger = LoggerFactory.getLogger(User.class);
	
	/*
	 * Primary key generated by userId
	 */
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;
	
	
	
	/*
	 * Required Information
	 */
	@Persistent
	private String userId;
	
	@XmlTransient
	@Persistent
	private String password;
	
	@Persistent
	private String idNumber;
	
	@XmlTransient
	@Persistent
	private String deviceSN;
	
	
	
	/*
	 * Security 
	 */
	@XmlTransient
	@Persistent(serialized="true")
	private AES crypto;
	
	@XmlTransient
	@Persistent
	private byte[] pin;
	
	
	
	/*
	 * User Account Information
	 */
	@XmlTransient
	@Persistent
	private boolean isActive;
	
	@XmlTransient
	@Persistent
	private Date authenticated;
	
	@Persistent
	private List<Long> articles;
	
	
	/*
	 * Constructors
	 */
	public User() {}
	
	public User(
			String userId, String password, 
			String idNumber, String deviceSN) throws Exception {
		this.userId = userId;
		this.password = password;
		this.idNumber = idNumber;
		this.deviceSN = deviceSN;
		
		this.crypto = new AES();
		
		this.pin = this.crypto.encode(
				"userId=" + userId + "&idNumber=" + idNumber 
				+ "&deviceSN=" + deviceSN);
		this.articles = new ArrayList<Long>();
	}

	
	
	/*
	 * Helpers
	 */
	
	
	
	/*
	 * Getters and Setters
	 */
	public Key getKey() {
		return key;
	}

	public void setKey(Key key) {
		this.key = key;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getIdNumber() {
		return idNumber;
	}

	public void setIdNumber(String idNumber) {
		this.idNumber = idNumber;
	}

	public String getDeviceSN() {
		return deviceSN;
	}

	public void setDeviceSN(String deviceSN) {
		this.deviceSN = deviceSN;
	}
	
	public AES getCrypto() {
		return crypto;
	}

	public byte[] getPin() { //this method is used only once when User object is created
		return pin;
	}

	public List<Long> getArticles() {
		return articles;
	}

	public void setArticles(List<Long> articles) {
		this.articles = articles;
	}

	public PIN login(String oldPin) {
		
		logger.info("login starts");
		logger.info("user object: " + this.toString());
		
		
		this.isActive = true;
		this.authenticated = new Date();
		
		PIN ret = new PIN();
		ret.setResult(PIN.OK);
		ret.setMessage("Successfully authenticated user");
		ret.setPin(new String(this.pin));
		
		return ret;
		
		/*
		String decoded;
		try {
			decoded = this.crypto.decode(oldPin.getBytes());
		} catch(Exception e) {
			decoded = null;
		}
		if (decoded == null) {
			return null;
		}
		
		
		String[] t = decoded.split("=|&");
		if (t[0].equals("userId")
				&& t[1].equals(getUserId())
				&& t[2].equals("idNumber")
				&& t[3].equals(getIdNumber())
				&& t[4].equals("deviceSN")
				&& t[5].equals(getDeviceSN())
		) {
			
			logger.info("PIN confirmed");
			try {
				this.crypto = new AES();
			} catch (Exception e) {
				e.printStackTrace();
			}
			this.pin = this.crypto.encode(
					"userId=" + userId + "&idNumber=" + idNumber 
					+ "&deviceSN=" + deviceSN);
			this.isActive = true;
			this.authenticated = new Date();
			
			PIN ret = new PIN();
			ret.setResult(PIN.OK);
			ret.setMessage("Successfully authenticated user");
			ret.setPin(this.pin);
			
			return ret;
		}
		logger.info("Invalid PIN");
		return null;
		*/
	}

	public boolean isActive() {
		// TODO Auto-generated method stub
		return this.isActive;
	}

	public boolean authenticate(String userPin) {
		
		logger.info("authenticate starts");
		logger.info("user object: " + this.toString());
		
		return true;
		/*
		
		String decoded;
		try {
			decoded = this.crypto.decode(userPin.getBytes());
		} catch(Exception e) {
			decoded = null;
		}
		if (decoded == null) {
			return false;
		}
		
		
		String[] t = decoded.split("=|&");
		if (t[0].equals("userId")
				&& t[1].equals(getUserId())
				&& t[2].equals("idNumber")
				&& t[3].equals(getIdNumber())
				&& t[4].equals("deviceSN")
				&& t[5].equals(getDeviceSN())
		) {
			return true;
		} else {
			return false;
		}
		*/
	}

	
	
}